<template>
  <div class="container">
    <designer-tools
      class="designer-tools"
      @menu-node="addNode"
      @menu-remove="removeItem"
      @menu-dowlond="downloadGraph"
    />
    <div class="designer-main" ref="chart" />
    <designer-editor class="designer-editor" ref="editor" @save="updateModel" />
  </div>
</template>

<script lang="ts">
import DesignerTools from './components/DesignerTools.vue'
import DesignerEditor from './components/DesignerEditor.vue'
import G6 from '@antv/g6'
import { useMessage } from '@/hooks/useMessage'
import { modelGraphApi } from '@/api/modelDesigner'
import { NodeType } from './types/item'

import { defineComponent, ref, onMounted } from 'vue'
export default defineComponent({
  name: 'ModelDesigner',
  components: { DesignerTools, DesignerEditor },
  props: {},
  setup() {
    const chart = ref()
    const editor = ref()

    let graph = null
    let currentItem = null
    /** 添加节点 */
    function addNode({ x, y }) {
      const point = graph.getPointByClient(x, y)
      graph.addItem('node', {
        type: 'circle',
        size: 50,
        x: point.x,
        y: point.y,
      })
      graph.refresh()
    }
    // 更新模型
    function updateModel(modleData) {
      console.log(currentItem, modleData)
      const item = graph.findById(currentItem.id)
      item.update(modleData)
    }
    /** 删除元素 */
    function removeItem() {
      if (!currentItem) {
        useMessage.warning('请选中要删除的元素')
        return
      }
      const item = graph.findById(currentItem.id)
      if (item.getType() === 'node') {
        // 获取与 node 关联的所有边
        const edges = item.getEdges()
        if (edges.length > 0) {
          useMessage.warning('请先删除该节点连接的边')
        }
      }
      graph.removeItem(item)
      currentItem = null
    }

    /**
     * 下载拓扑数据
     */
    function downloadGraph(callback) {
      const nodes = graph.save().nodes.map((d: NodeType) => {
        return {
          id: d.id,
          type: d.type,
          label: d.label,
          size: d.size,
          style: {
            fill: d.style.fill,
          },
          x: d.x,
          y: d.y,
        }
      })
      const edges = graph.save().edges.map((d) => {
        return {
          id: d.id,
          source: d.source,
          target: d.target,
          type: d.type,
        }
      })

      callback({ nodes, edges })
    }

    onMounted(() => {
      graph = new G6.Graph({
        container: chart.value,
        defaultEdge: {
          style: {
            lineWidth: 3,
            lineAppendWidth: 5,
            endArrow: true,
          },
          labelCfg: {
            autoRotate: true,
          },
        },
        modes: {
          default: [
            'drag-canvas',
            'zoom-canvas',
            'drag-node',
            { type: 'create-edge', key: 'shift' },
          ],
        },
      })

      graph.on('node:click', (evt) => {
        const model = evt.item.getModel()
        currentItem = model
        editor.value.open('node', model)
      })
      graph.on('edge:click', (evt) => {
        const model = evt.item.getModel()
        currentItem = model
        editor.value.open('edge', model)
      })
      graph.on('aftercreateedge', (e) => {
        const edges = graph.save().edges
        G6.Util.processParallelEdges(edges)
        graph.getEdges().forEach((edge, i) => {
          graph.updateItem(edge, {
            curveOffset: edges[i].curveOffset,
            curvePosition: edges[i].curvePosition,
          })
        })
      })

      modelGraphApi().then(({ data }) => {
        G6.Util.processParallelEdges(data.edges)
        graph.data(data)
        graph.render()
      })
    })

    return {
      chart,
      editor,
      addNode,
      removeItem,
      updateModel,
      downloadGraph,
    }
  },
})
</script>

<style lang="scss" scoped>
.container {
  position: relative;
  height: 100%;
  .designer-tools {
    background: aquamarine;
    height: 50px;
  }
  .designer-main {
    background-color: #fff;
    height: calc(100% - 50px);
  }
  .designer-editor {
    position: absolute;
    padding: 20px;
    top: 0;
    right: 0;
    width: 30vw;
    height: 50vh;
    background: darkkhaki;
  }
}
</style>
